Skip to main content

Cutting Möbius Strip in Makie.jl

·546 words

We are tasked with visualizing the process of cutting a Möbius strip in half, and color the two sides with different colors using Makie.jl, a powerful plotting library in Julia.

We will use the following parameterization of the Möbius strip:

$$ \begin{align*}x&=\left(r+(2-v)\cos\frac{u}{2}\right)\cos\,u\\y&=\left(r+(2-v)\cos\frac{u}{2}\right)\sin\,u\\z&=(2-v)\sin\frac{u}{2}\end{align*} $$

where $0\leq v \leq 2$, $0\leq u \leq 4\pi$ and $r$ controls the size. It has normal vector

$$ \begin{pmatrix} \frac12\left(r\sin\frac{u}{2}-r\sin\frac{3u}{2}-2(v-2)\sin\,u\sin^2\frac{u}{2}\right) \\ \frac12\left((v-2)(\sin^2 u+\cos\,u)-2r\sin\frac{u}{2} \sin\,u\right) \\ \left(r-(v-2)\cos\frac{u}{2}\right)\cos\frac{u}{2} \end{pmatrix}. $$

To cut the strip, we limit $v \leq v_{cut}$, where $v_{cut}$ is a parameter that we will vary from $0$ to $2$. When $v_{cut} = 2$, we have the full strip.

Preliminaries #

The following code is tested in Julia 1.11.6 with Makie 0.24.6. We will be using the GLMakie backend for fast and interactive 3D rendering (see Makie Docs for installation instructions).

Problem Setup #

using GLMakie

# Define the parametric equations for the Mobius strip
r = 5
x(u, v) = (r + (2 - v) * cos(u / 2)) * cos(u)
y(u, v) = (r + (2 - v) * cos(u / 2)) * sin(u)
z(u, v) = (2 - v) * sin(u / 2)
# normal vector
n(u, v) = begin
    x = 1 / 2 * (r * sin(u / 2) - r * sin(3 / 2 * u) - 2 * (v - 2) * sin(u) * sin(u / 2)^2)
    y = 1 / 2 * ((v - 2) * (sin(u)^2 + cos(u)) - 2r * sin(u / 2) * sin(u))
    z = (r - (v - 2) * cos(u / 2)) * cos(u / 2)
    norm = sqrt(x^2 + y^2 + z^2)
    (x / norm, y / norm, z / norm)
end

Simple Surface Plot #

We will plot the full Möbius strip first with minimal styling.

fig = Figure(resolution=(800, 600))
ax = Axis3(fig[1, 1],
    alignmode=Outside(-300),
    aspect=(1, 1, 0.3),
    viewmode=:fit,
    protrusions=(0, 0, 0, 0)
)
hidedecorations!(ax)
hidespines!(ax)
# u goes from 0 to 4π
u = LinRange(0, 4pi, 300)
# v goes from 0 to 2
v = LinRange(0, 2, 20)
# Generate the surface points
X = x.(u, v')
Y = y.(u, v')
Z = z.(u, v')
# use u value for coloring
color = sin.(u) * ones(length(v))'

surface!(ax, X, Y, Z; color=color, shading=false, colormap=:reds)
fig

results in:

Simple Surface Plot

Cutting the Strip #

To cut the strip, modify the range of v to go from 0 to v_cut.

...
v_cut = 4/3
v = LinRange(0, v_cut, 20)
...

results in:

Simple Surface Plot (Cut)

Coloring the Two Sides #

After cutting, the strip has two sides (orientable). We can color them differently based on whether the normal vector is pointing towards or away from the viewer. In fact, this is fairly simple to do in raw openGL with custom shaders, but GLMakie does not support this level of customization. Instead, we will use a workaround by plotting two surfaces with slightly offset along the normal vector. Add the following code after the surface! call above.

# shift vertices along normal
norms = n.(u, v')
c = 0.001
X1 = X .+ c * getindex.(norms, 1)
Y1 = Y .+ c * getindex.(norms, 2)
Z1 = Z .+ c * getindex.(norms, 3)
surface!(ax, X1, Y1, Z1; color=color, shading=false, colormap=:blues)

results in:

Cutting Möbius Strip (Two Sides)

Animation #

Finally, we can animate by rotating the view.

Yang-Yang Xu
Author
Yang-Yang Xu
some guy